package my.classes;

import my.classes.ClassExamples.InnerMember;
import my.classes.ClassExamples.StaticMember;
import my.classes.ClassExamples.StaticMemberPro;

import java.lang.reflect.InvocationTargetException;

public class ClassExamples
{
	int memberVar = 4;
	int bar;
	
	public void localClassExample()
	{
		//Local Class
		class ClassInMethod
		{
			public void print()
			{
				System.out.println("I am a local class");
			}
		}
		
		ClassInMethod local = new ClassInMethod();
		local.print();
	}
	
	public void innerClassExample(final int num) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
	{
		Object o = new Object() 
		{	
		    // this is legal and will be used instead of the param	
			//int num = 4;
			public void print()
			{
				// num has to be final on the param, to guard against any changes
				System.out.println("Print param " + num);
			}
		};
		o.getClass().getMethod("print", null).invoke(o, null);
	}
	
	public void memberClassExample()
	{
		// these classes can be constructed in the context of an instance without reference to the containing class, see main method
		InnerMember iM  = new InnerMember();
		InnerMemberPub iMP  = new InnerMemberPub();
		InnerMemberPriv iMV  = new InnerMemberPriv();
	}
	
	//Member Class
	class InnerMember
	{		
	}
	
	//Member Class
	public class InnerMemberPub
	{	
	}
	
	//Member Class
	private class InnerMemberPriv
	{		
	}
	
	//Static Member Class
	public static class StaticMember
	{	
		public void printPublicStatic()
		{
			// This isn't legal static class are top level classes not inner classes, it can't see memberVar
			//System.out.println("memberVar = " + memberVar);
			
			// this is legal because it's creating a top level class to access the var
			ClassExamples cE = new ClassExamples();
			System.out.println("memberVar = " + cE.memberVar);
			
			// can be accessed in class
			StaticMemberPriv f = new StaticMemberPriv();
		}
	}
	
	//Static Member Class
	private static class StaticMemberPriv
	{
		// can't be seen or touched outside of this class
	}
	
	//Static Member Class
	static class StaticMemberPro
	{
		// can be seen or touched in package of this class
	}
}


/**
 * You can't a public class not enclosed in the main class
 * 
public class NotAllowedClass
{	
}
*/

/**
 * This is not an inner class, it is a separate class
 */
class AllowedClass
{	
}

class ClassTester
{
	public static void main(String [] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
	{
		ClassExamples cE = new ClassExamples();
		cE.localClassExample();
		cE.innerClassExample(2);
		
		StaticMember sM = new ClassExamples.StaticMember();
		sM.printPublicStatic();
		
		StaticMemberPro sMP = new ClassExamples.StaticMemberPro();
		
		// This isn't allowed outside of the class ClassExample
		//StaticMemberPriv sMP = new ClassExamples.StaticMemberPriv();
		
		// these classes can be constructed in the context of an instance without that they can't be, you
		// can fully qualify the class with the outer class name or import it and use the inner class only name
		InnerMember iM  = cE.new InnerMember();
		ClassExamples.InnerMemberPub iMP  = cE.new InnerMemberPub();
		
		//This isn't allowed outside of the class ClassExample
		//ClassExamples.InnerMemberPriv iMV  = cE.new InnerMemberPriv();

        if (cE instanceof ClassExamples)
        {
            System.out.println("Instance of this class");
        }

        if(!(null instanceof StaticMember))
        {
           System.out.println("Null isn't instance of anything");
        }
	}
}

